﻿using System;

namespace iStudio.Library.Dsp
{
    public class Effect
    {
        /// <summary>
        /// Normalizes samples to interval: [-1, 1]
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="offset">offset to start</param>
        /// <param name="count">count of samples</param>
        public static void Normalize(float[] input, int offset, int count)
        {
            float max = float.MinValue;

            for (int i = offset; i < (offset + count); i++)
            {
                if (Math.Abs(input[i]) > max)
                {
                    max = Math.Abs(input[i]);
                }
            }

            for (int i = offset; i < (offset + count); i++)
            {
                input[i] = input[i] / max;
            }
        }

        /// <summary>
        /// Normalizes samples to interval: [-1, 1]
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="count">count of samples</param>
        public static void Normalize(float[] input, int count)
        {
            Normalize (input, 0, count);
        }

        /// <summary>
        /// Normalizes samples to interval: [-1, 1]
        /// </summary>
        /// <param name="input">input samples</param>
        public static void Normalize(float[] input)
        {
            Normalize (input, 0, input.Length);
        }

        /// <summary>
        /// Chorus effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="sampleRate">sample rate in Hz</param>
        /// <param name="amplitudes">amplitudes</param>
        /// <param name="delays">offset positions</param>
        /// <returns>samples with chorus effect</returns>
        public static float[] Chorus (float[] input, int sampleRate, float[] amplitudes, int[] delays)
        {
            float[] output = new float[input.Length + delays[delays.Length - 1] * 2 * sampleRate / 1000];

            for (int x = 0; x < delays.Length + 1; x++)
            {
                for (int i = 0; i < input.Length; i++)
                {
                    if (x != delays.Length)
                    {
                        int index = delays[x] * 2 * sampleRate / 1000;
                        output[i + index] = output[i + index] + (input[i] * amplitudes[x]);
                    }
                    else
                    {
                        output[i] = output[i] + input[i];
                    }
                }
            }

            Normalize (output);

            return output;
        }

        /// <summary>
        /// Flanger effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="sampleRate">sample rate</param>
        /// <param name="maxDelay">maximum delay in miliseconds</param>
        /// <param name="frequency">flanger frequency</param>
        /// <param name="amplitude">flanger amplitude</param>
        /// <returns>samples with flanger effect</returns>
        public static void Flanger (float[] input, int sampleRate, int maxDelay, int frequency, double amplitude)
        {
            int max = maxDelay * sampleRate / 1000;

            //
            // The rest of the audio
            //

            for (int i = max + 1; i < input.Length; i++)
            {
                double sin = Math.Abs(Math.Sin(2 * Math.PI * i * (frequency / (double)sampleRate)));
                int delay = (int)(sin * max);

                input[i] = (float)(amplitude * input[i]) + (float)(amplitude * input[i - delay]);
            }
        }

        /// <summary>
        /// Fade in effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="sampleRate">sample rate of the audio </param>
        /// <param name="length">length of effect in miliseconds</param>
        public static void FadeIn (float[] input, int sampleRate, int length)
        {
            FadeIn (input, length * sampleRate / 1000);
        }

        /// <summary>
        /// Fade in effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="length">length of effect in samples</param>
        public static void FadeIn(float[] input, int length)
        {
            for (int i = 0; i < length; i++)
            {
                float factor = (i / (float)length);

                input[i] = input[i] * factor;
            }
        }

        /// <summary>
        /// Fade out effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="sampleRate">channel sample rate</param>
        /// <param name="length">length of effect in miliseconds</param>
        public static void FadeOut (float[] input, int sampleRate, int length)
        {
            FadeOut (input, length * sampleRate / 1000);
        }

        /// <summary>
        /// Fade out effect
        /// </summary>
        /// <param name="input">input samples</param>
        /// <param name="length">length of effect in samples</param>
        public static void FadeOut (float[] input, int length)
        {
            for (int i = input.Length - length; i < input.Length; i++)
            {
                float factor = 1.0f - ( (i - (input.Length - length)) / (float) length);

                input[i] = input[i] * factor;
            }
        }
    }
}
